---
title: Vertex and Fragment Shader Programming  
---

A `Pass` represents a single GPU rendering process, so each `Pass` must include both a vertex shader and a fragment shader. In ShaderLab, the `VertexShader` and `FragmentShader` keywords specify their entry functions.

```glsl showLineNumbers {4-5}
...
Pass "0" {
  ...
  VertexShader = vert;
  FragmentShader = frag;

  v2f vert(a2v o) {
    ...
  }

  ...

  void frag(v2f i) {
    ...
  }
  ...
}
```

## Attribute and Varying Variable Declarations  

Like traditional GLSL shaders, ShaderLab uses **Attribute** and **Uniform** variables to receive rendering data from the CPU. **Varying variables** are used to pass data between vertex and fragment shaders. Unlike traditional GLSL, ShaderLab declares these variables using **structs** and **shader entry function signatures**.

```glsl showLineNumbers {13, 16, 21, 27-28}
struct Attributes {
  vec3 POSITION;
  vec4 COLOR_0;
  ...
}

struct Varyings {
    vec2 uv;
    vec3 position;
    ...
}
...
Varyings vert(Attributes attr) {
    Varyings vary;
    ...
    vary.position = attr.Position;
    ...
    return vary;
}

void frag(Varyings vary) {
    ...
    gl_FragColor = vary.COLOR_0;
}

...
VertexShader = vert;
FragmentShader = frag;
```

## MRT (Multiple Render Targets)  

ShaderLab supports both **GLSL 100** and **GLSL 300** syntax, so you can use either approach to specify MRT:

### 1. Using `gl_FragData[i]`  
```glsl showLineNumbers {2-3}
void main(v2f input) {
  gl_FragData[0] = vec4(1.,0.,0.,1.);     // render target 0
  gl_FragData[1] = vec4(1.,0.,0.,1.);     // render target 1
}
```

### 2. Using a Return Struct  
```glsl showLineNumbers {1-4}
struct mrt {
  layout(location = 0) vec4 fragColor0;   // render target 0
  layout(location = 1) vec4 fragColor1;   // render target 1
}

mrt main(v2f input) {
  mrt output;
  output.fragColor0 = vec4(1.,0.,0.,1.);
  output.fragColor1 = vec4(1.,0.,0.,1.);
  return output;
}
```

## Macros  

ShaderLab currently supports the following GLSL macro operations:

| Macro | Description |
| :-: | :- |
| `#define` | Same as GLSL |
| `#undef` | Same as GLSL |
| `#if` | Same as GLSL |
| `#ifdef` | Same as GLSL |
| `#ifndef` | Same as GLSL |
| `#else` | Same as GLSL |
| `#elif` | Same as GLSL |
| `#endif` | Same as GLSL |
| `defined` | Same as GLSL |
| `#include` | **ShaderLab-specific**: Used for code segment inclusion. See [documentation](./chunk) for details |

All macros except `#include` follow standard GLSL behavior. For detailed usage, refer to the [GLSL specification](https://registry.khronos.org/OpenGL/specs/es/3.0/GLSL_ES_Specification_3.00.pdf).

<Callout type="warning">  
ShaderLab macros are expanded during the preprocessor phase and **cannot affect ShaderLab structure parsing**. This means keywords like `Shader`, `SubShader`, `Pass`, `EditorProperties`, and `EditorMacros` cannot appear inside conditional macros like `#ifdef`.  
</Callout>